#pragma once
#include"SimulatedAnnealing.h"
#include<time.h>

#include"LocalSearch.h"
#include"RandomGenerator.h"

using namespace std;

Solution SimulatedAnnealing::Run(Solution& solution , const double timeLimit)
{
	RandomGenReal<double> randomDouble(0.0 , 1.0);
	double highTemperature = _startTemperature;
	double coolRate = _coolRate;
	const double CoolRateMax = 0.9998;
	const int MaxNumJump = 2;

	int scoreBest = solution.getEvaluate();
	int scoreNow = scoreBest;
	Solution bestSolution = solution;
	Solution tempSolution = solution;
	const double startTime = clock();

	while(true)
	{
		double temperature = highTemperature;
		while(temperature > _finalTemprature) 
		{
			int jumpCounter = 0;

			for (int i = 0 ; i < _iterateLength  ; ++i)
			{
				if((clock() - startTime) / CLOCKS_PER_SEC > timeLimit)
				{
					return bestSolution;
				}
				else if (jumpCounter >= MaxNumJump)
				{
					break;
				}
				else
				{
					Solution neighbor = tempSolution.getRandomNeighbor();
					int neighborScore = neighbor.getEvaluate();
					double doorsill = randomDouble();
					if (neighborScore <= scoreNow || exp((scoreNow - neighborScore) / temperature) > doorsill)
					{
						scoreNow = neighborScore;
						tempSolution = neighbor;
						if(neighborScore < scoreBest)
						{
							bestSolution = neighbor;
							scoreBest = neighborScore;
						}
						++jumpCounter;
					}
				}
			}
			temperature *= coolRate;
		}
		coolRate += (1.0 - coolRate) / 2.0;
		coolRate = min(CoolRateMax , coolRate);
	}
}